package com.example.wangzh.developkit.utils;


import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;

import androidx.annotation.IntDef;

import com.example.wangzh.developkit.base.MyApplication;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Type;
import java.util.Set;

/**
 * SharedPreferences:共享偏好，用来做数据存储，通过xml，存放标记性数据和设置信息
 */
@SuppressWarnings({"unused", "RedundantSuppression"})
@SuppressLint("ApplySharedPref")

public class PreferenceUtils {
    public static final int MODE_PRIVATE = 0x0000;
    public static final int MODE_WORLD_READABLE = 0x0001;
    public static final int MODE_WORLD_WRITEABLE = 1 << 1;
    public static final int MODE_MULTI_PROCESS = 1 << 2;

    @SuppressLint({"WorldReadableFiles", "WorldWriteableFiles"})
    @IntDef(flag = true, value = {
            MODE_PRIVATE,
            MODE_WORLD_READABLE,
            MODE_WORLD_WRITEABLE,
            MODE_MULTI_PROCESS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface PreferencesMode {
    }

    //默认文件名称为config
    private static final String DEFAULT_PREFERENCE_NAME = "config";

    @SuppressLint("StaticFieldLeak")
    private static PreferenceUtils instance;

    private SharedPreferences sharedPreferences;
    private final Gson gson;
    private final Context context = MyApplication.getContext();
    private String preferenceName = DEFAULT_PREFERENCE_NAME;
    private @PreferencesMode
    int mode = MODE_PRIVATE;

    private PreferenceUtils() {
        sharedPreferences = context.getSharedPreferences(preferenceName, mode);
        gson = new Gson();
    }

    public synchronized static PreferenceUtils getInstance() {
        if (instance == null) {
            instance = new PreferenceUtils();
        }
        return instance;
    }

    private PreferenceUtils setPreferenceName(String name) {
        if (name != null && !("" + preferenceName).equals(name)) {
            this.preferenceName = name;
            sharedPreferences = context.getSharedPreferences(preferenceName, mode);
        }
        return this;
    }

    private PreferenceUtils setPreferenceMode(@PreferencesMode int mode) {
        if (mode != this.mode) {
            this.mode = mode;
            sharedPreferences = context.getSharedPreferences(preferenceName, mode);
        }
        return this;
    }


    private PreferenceUtils setPreferenceProp(String name, @PreferencesMode int mode) {
        boolean hasChange = false;
        if (name != null && !("" + preferenceName).equals(name)) {
            this.preferenceName = name;
            hasChange = true;
        }
        if (mode != this.mode) {
            this.mode = mode;
            hasChange = true;
        }
        if (hasChange) {
            sharedPreferences = context.getSharedPreferences(preferenceName, mode);
        }
        return this;
    }

    private SharedPreferences getSharedPreferences() {
        if (sharedPreferences == null) {
            sharedPreferences = context.getSharedPreferences(preferenceName, mode);
        }
        return sharedPreferences;
    }

    public void putInt(String key, int value) {
        getSharedPreferences().edit().putInt(key, value).commit();
    }

    public int getInt(String key, int defValue) {
        return getSharedPreferences().getInt(key, defValue);
    }

    public void putLong(String key, long value) {
        getSharedPreferences().edit().putLong(key, value).commit();
    }

    public long getLong(String key, long defValue) {
        return getSharedPreferences().getLong(key, defValue);
    }

    public void putFloat(String key, float value) {
        getSharedPreferences().edit().putFloat(key, value).commit();
    }

    public float getFloat(String key, float defValue) {
        return getSharedPreferences().getFloat(key, defValue);
    }

    public void putBoolean(String key, boolean value) {
        getSharedPreferences().edit().putBoolean(key, value).commit();
    }

    public boolean getBoolean(String key, boolean value) {
        return getSharedPreferences().getBoolean(key, value);
    }

    public void putString(String key, String value) {
        getSharedPreferences().edit().putString(key, value).commit();
    }

    public String getString(String key, String defValue) {
        return getSharedPreferences().getString(key, defValue);
    }

    public Set<String> getStringSet(String key, Set<String> defValue) {
        return getSharedPreferences().getStringSet(key, defValue);
    }

    public void putStringSet(String key, Set<String> value) {
        getSharedPreferences().edit().putStringSet(key, value).commit();
    }

    /**
     * 写入Object变量至sharedPreferences中
     *
     * @param key   存储节点名称
     * @param value 存储节点的值T
     */
    public <T> void putObject(String key, T value) throws NullPointerException {
        getSharedPreferences().edit().putString(key, new Gson().toJson(value)).commit();
    }

    /**
     * 读取Object从sharedPreferences中
     * type务必与T的类型保持一致，否则会返回空指针
     *
     * @param key 存储节点名称
     * @return 返回默认值或者此节点读取到的结果
     */
    public <T> T getObject(String key, Type type) {
        String str = getSharedPreferences().getString(key, "");
        T t = null;
        try {
            t = gson.fromJson(str, type);
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 读取Object从sharedPreferences中
     * cls务必与T的类型保持一致，否则会返回空指针
     *
     * @param key 存储节点名称
     * @return 返回默认值或者此节点读取到的结果
     */
    public <T> T getObject(String key, Class<T> cls) {
        String str = getSharedPreferences().getString(key, "");
        T t = null;
        try {
            t = gson.fromJson(str, cls);
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 从sharedPreferences中移除指定节点
     *
     * @param key 需要移除节点的名称
     */
    public void remove(String key) {
        getSharedPreferences().edit().remove(key).commit();
    }
}